import time
from datetime import datetime
from email.utils import parsedate_tz
import email.Errors

from mailmigration.mm_time import FixedOffset, Local

def meets_criteria(opts, msg):
    #We include all messages by default
    result = True
    for c in opts.criteria:
        if c == 'dry':
            result = False
            opts.logger.debug('Dry run active, skipped message %s' % msg['message-id'])
        elif c == 'begindate':
            #from IPython.Shell import IPShellEmbed
            #IPShellEmbed(argv=['-colors', 'NoColor'])()
            if not msg.date >= opts.begindate:
                result = False
                opts.logger.debug('Message date "%s" not after begin date %s',
                                str(msg.date), str(opts.begindate))
        elif c == 'enddate':
            if not msg.date <= opts.enddate:
                result = False
                opts.logger.debug('Message date "%s" not before end date %s',
                                str(msg.date), str(opts.enddate))
    return result

def process_mailbox(opts, args, src_mb, dest_mb):
    block_piece = 0
    pos = 0
    msg_count = len(src_mb)
    for k in src_mb.iterkeys():
        try:
            m = src_mb[k]
        except email.Errors.MessageParseError, err:
            opts.logger.error(err)
            pos += 1
            continue                # The message is malformed. Just leave it.
        if m['date'] is None:
            opts.logger.warning('Message missing Date header: %s',
                                m['message-id'])
            m.date = opts.started
        else:
            tt = list(parsedate_tz(m['date']))
            if tt[-1] is None:
                opts.logger.warning('Message missing timezone in Date header: %s',
                                    m['message-id'])
                m.date = datetime(*(tt[:7] + [Local]))
            else:
                m.date = datetime(*(tt[:7] + [FixedOffset(tt[-1]/60, str(tt[-1]/60))]))
        if meets_criteria(opts, m):
            if hasattr(m, 'set_date'):
                mstamp = time.mktime(m.date.utctimetuple())
                if round(m.get_date()) >= round(mstamp):
                    m.set_date(mstamp)
            #This is about the only action not surrounded by a try...except
            #If we start seeing reports of errors here they can be handled
            #appropriately
            msg_id = dest_mb.add(m)

            block_piece += 1
            pos += 1
            pct_done = (pos/float(msg_count))*100
            opts.logger.debug('Added message: %s (%d of %d, %.1f%% done)',
                                msg_id,
                                pos,
                                msg_count,
                                pct_done)
            if hasattr(opts, 'delete') and opts.delete:
                if not opts.dry:
                    src_mb.remove(k)
                    opts.logger.debug('Deleted message: %s (%d of %d, %.1f%% done)',
                                        k,
                                        pos,
                                        msg_count,
                                        pct_done)
            if block_piece >= opts.blocksize:
                #Only option so far that affects the source mailbox is delete
                #so we only flush it if that is set
                #(to avoid writing out a potentially large mbox file)
                if hasattr(opts, 'delete') and opts.delete:
                    src_mb.flush()
                    opts.logger.info('Flushed mailbox: %s (%d of %d, %.1f%% done)',
                                        args[0],
                                        pos,
                                        msg_count,
                                        pct_done)
                dest_mb.flush()
                opts.logger.info('Flushed mailbox: %s (%d of %d, %.1f%% done)',
                                    args[1],
                                    pos,
                                    msg_count,
                                    pct_done)
                block_piece = 0

